package com.ubix.kiosoft2;

import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.ubix.kiosoft2.services.BluetoothLeService;
import com.ubix.kiosoft2.utils.CommonDialog;
import com.ubix.kiosoft2.utils.Constants;
import com.ubix.kiosoft2.utils.Utils;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

import static com.ubix.kiosoft2.EventReader.EVENT_TYPE_CLEAR_SCREEN;
import static com.ubix.kiosoft2.EventReader.EVENT_TYPE_RESTORE_PAGE;
import static com.ubix.kiosoft2.EventReader.EVENT_TYPE_START_SCAN_ERROR;
import static com.ubix.kiosoft2.EventReader.EVENT_TYPE_STOP_SCAN_ERROR;


/**
 * @Created by taylor on 9/27/18.
 */

public class DemoActivity extends AppCompatActivity {

    private String TAG = "DemosPage";
    private Timer mTimer;

    private ProgressDialog progressDialog;
    private Context mContext;

    private ScanCallback mScanCallback;
    private BluetoothLeService mBluetoothLeService;
    private static final long SCAN_PERIOD = 5000 * 2; // 10s
    private static final int PACKAGE_ARRAY_SIZE = 1024 * 2;  // 数据包大小

    private int tryTimes = 1;

    private boolean mScanning;
    private boolean deviceFound = false;
    private boolean isTimeOut = false;
    private boolean mProgressed = false;

    //    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss:SSS");

    /**
     * 名称对比-扫码输入
     */
    private String deviceAddress;

    /**
     * 名称对比-手动输入
     */
    private String mDeviceName = "";

    private StringBuffer responseBuf;
    static final int MACHINE_IDLE = 0;
    static final int CHECK_VENDOR_ID = 1;
    static final int GET_PRICE = 2;
    static final int START_CYCLE_EXTEND = 3;
    static final int END_CYCLE = 4;
    static final int GET_FIRMWARES_VERSION = 5;
    static final int GET_INFORMATION_REMANIN_TIME = 6;
    static final int GET_INFORMATION_MACHINE_TYPE = 7;
    static final int GET_INFORMATION_MACHINE_STATUS = 8;
    static final int DO_COIN_COLLECTION = 9;
    private int currentProcess = MACHINE_IDLE;

    @SuppressWarnings("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0x01:
                    startME51DataTimerDown();
                    break;
                case 0x02:
                    startME51ActiveDisconnectDown();
                    break;
                case 0x03:
                    handleSendDataFailure();
                    break;

                case 0x11:
                    if (mME51DataResponseTimer != null) {
                        mME51DataResponseTimer.cancel();
                    }
                    break;
                case 0x22:
                    if (mME51DisconnectTimer != null) {
                        mME51DisconnectTimer.cancel();
                    }
                    break;
            }
        }
    };

    @BindView(R.id.et_bt_cycle_times)
    EditText etCycleTimes;
    @BindView(R.id.et_bt_times_in_cycle)
    EditText etTimesInCycle;
    @BindView(R.id.et_bt_name)
    EditText etBtName;

    @BindView(R.id.ll_btn_app_active_mode)
    LinearLayout llAppActive;

    @BindView(R.id.ll_btn_me51_active_mode)
    LinearLayout llME51Active;

    @BindView(R.id.btn_start_scan)
    Button btnScan;

    @BindView(R.id.ll_root_progress)
    LinearLayout llRootProgress;
    @BindView(R.id.tv_current_version)
    TextView tvCurrentVersion;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        // Code to manage Service lifecycle.
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            BluetoothLeService.LocalBinder binder = (BluetoothLeService.LocalBinder) service;
            mBluetoothLeService = binder.getService();
            if (!mBluetoothLeService.initialize(DemoActivity.this)) {
                Log.e(TAG, "Unable to initialize Bluetooth");
                finish();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.i(TAG, "onServiceDisconnected: service 解绑了");
            mBluetoothLeService = null;
        }
    };

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");// HH:mm:ss
    private String scanStartTime, scanEndTime;

    // ME51-数据返回 响应-倒计时
    private CountDownTimer mME51DataResponseTimer, mME51DisconnectTimer;

    private SharedPreferences me51Shared;
    private SharedPreferences.Editor mEditor;

    /**
     * test params
     */
    private boolean appActiveMode = true;
    private boolean testScanning = false;
    private int receiveCount = 0;
    private static int checkCount = 0;

    private boolean boolDisconnectDelay; // 全局控制: 主动模式下，断开后延时13秒
    private boolean boolContinueNextCycle; // 全局控制
    private boolean boolWaitingForME51Disconnect; // 全局控制: 等待ME51主动断开

    private boolean boolWaitingForOneCloseCycle; // 全局控制: 数据全部成功返回

    private int currentSendDataType; // 全局控制: 当前发送的数据类型 1 2 3

    private final String DEFAULT_BLE_NAME = "defaut_ble_name";
    //    private static final String C_BT_NAME = "00doos006000241241";
    private static final String C_BT_NAME = "00doos006000125125";

    //    private static final String C_BT_CYCLE_TIMES = "5";
//    private static final String C_BT_TIMES_IN_CYCLE = "10";
    private static final String C_BT_CYCLE_TIMES = "3";
    private static final String C_BT_TIMES_IN_CYCLE = "3";

    public static String mBtName;
    private int mCycleTimes = Integer.parseInt(C_BT_CYCLE_TIMES),
            mTimersInCycle = Integer.parseInt(C_BT_TIMES_IN_CYCLE);

    private Thread mCycleThread, mCommThread;

    /**
     * 测试结果
     */
    private int totalCycleSuccess, totalCycleFailure;
    private int totalConnectSuccess, totalConnectFailure, totalUnexceptedDisconnect;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_main_demo);
        mContext = this;

        ButterKnife.bind(this);
        EventBus.getDefault().register(this);

        me51Shared = getSharedPreferences("me51_demo_shared", MODE_PRIVATE);
        mEditor = me51Shared.edit();

        llRootProgress.setVisibility(View.INVISIBLE);
        responseBuf = new StringBuffer();

        tvCurrentVersion.setText("当前版本号 v" + getVersionName(this) + "_" + getVersionCode(this));

        initScanCallback();

        // Bind Bluetooth Le Service
        Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
        bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

        if (!Utils.locationEnabled(mContext)) {
            Utils.displayLocationSettingRequest(mContext, DemoActivity.this);
        } else if (Build.VERSION.SDK_INT >= 23 && !checkLocationPermission()) {
            requestLocationPermission();
        }
    }

    @OnClick({R.id.btn_default_set, R.id.btn_start_scan, R.id.ll_btn_app_active_mode, R.id.ll_btn_me51_active_mode,
            R.id.btn_goto_result})
    public void onCCC(View v) {
        switch (v.getId()) {
            case R.id.btn_default_set:
                etCycleTimes.setText(C_BT_CYCLE_TIMES);
                etTimesInCycle.setText(C_BT_TIMES_IN_CYCLE);
                etBtName.setText(C_BT_NAME);
                break;

            case R.id.btn_start_scan:
                if (testScanning) {
                    testScanning = false;
                    btnScan.setText("开始扫描");
                    llRootProgress.setVisibility(View.INVISIBLE);

                    mBluetoothLeService.stopScan(mScanCallback, mLeScanCallback);

                } else {
                    testScanning = true;
                    btnScan.setText("扫描中...");
                    llRootProgress.setVisibility(View.VISIBLE);

                    mBtName = etBtName.getText().toString().trim();  // Core Compare
                    mEditor.putString(DEFAULT_BLE_NAME, mBtName);
                    mEditor.apply();
                    mEditor.commit();

                    mCycleTimes = Integer.parseInt(etCycleTimes.getText().toString().trim());
                    mTimersInCycle = Integer.parseInt(etTimesInCycle.getText().toString().trim());

                    responseBuf.setLength(0);
                    receiveCount = 0;

                    totalCycleSuccess = 0;
                    totalCycleFailure = 0;
                    totalConnectSuccess = 0;
                    totalConnectFailure = 0;
                    totalUnexceptedDisconnect = 0;

                    EventBus.getDefault().post(new EventReader(EVENT_TYPE_CLEAR_SCREEN));
                    // todo jog:
//                    scanLeDevice(true, 2);
                    mCycleThread = new Thread(new CycleThread());
                    mCycleThread.start();
                }
                break;
            case R.id.ll_btn_app_active_mode:
                llAppActive.setBackgroundResource(R.drawable.bg_blue_select);
                llME51Active.setBackgroundResource(R.drawable.bg_gray_unselected);
                appActiveMode = true;
                break;

            case R.id.ll_btn_me51_active_mode:
                llME51Active.setBackgroundResource(R.drawable.bg_blue_select);
                llAppActive.setBackgroundResource(R.drawable.bg_gray_unselected);
                appActiveMode = false;
                break;

            case R.id.btn_goto_result:
                Intent i = new Intent(DemoActivity.this, ResultActivity.class);
                startActivity(i);
                break;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(mGattUpdateReceiver, BluetoothLeService.makeGattUpdateIntentFilter());

        // resume params
        mBtName = me51Shared.getString(DEFAULT_BLE_NAME, C_BT_NAME);

        etBtName.setText(mBtName);
        etCycleTimes.setText(mCycleTimes + "");
        etTimesInCycle.setText(mTimersInCycle + "");
    }

    @Override
    protected void onPause() {
        super.onPause();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
        unregisterReceiver(mGattUpdateReceiver);
        if (mBluetoothLeService != null) {
            mBluetoothLeService.disconnect();
            unbindService(mServiceConnection);
            mBluetoothLeService = null;
        }
    }

    /**
     * 周期控制线程
     */
    private class CycleThread extends Thread {

        private final String TAG_TS = "Cycle_T";
        private boolean inRunning;

        public CycleThread() {
            inRunning = true;
        }

        @Override
        public void run() {
            while (mCycleTimes > 0) {     // 单个周期内
                if (Thread.currentThread().isInterrupted()) {
                    break;  // 强制退出
                }
                if (inRunning) {
                    Log.e(TAG, "##### [Cycle" + mCycleTimes + "] #####");
                    try {
                        scanStartTime = simpleDateFormat.format(new Date(System.currentTimeMillis()));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    scanLeDevice(true, 2);
                    boolContinueNextCycle = false;
                    while (!boolContinueNextCycle) {
                        try {
                            Thread.sleep(1000);
                            Log.i(TAG, "--- waiting for [3]sendData completed ---");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    /**
                     * 一个周期结束则断开
                     * */
                    mCycleTimes -= 1;
                    mTimersInCycle = Integer.parseInt(etTimesInCycle.getText().toString().trim());  // todo jog: 【新周期-恢复参数】

                    if (appActiveMode) {  // app active
                        EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n【APP主动】断开蓝牙连接\n"));
                        disconnectBt();
                    } else {  // ME51 active
                        boolWaitingForME51Disconnect = false;
                        mHandler.sendEmptyMessage(0x02);
                        while (!boolWaitingForME51Disconnect) {
                            try {
                                Thread.sleep(1000);
                                Log.i(TAG, "--- waiting for [2]ME51 active disconnect ---");
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        EventBus.getDefault().post(new EventReader("\n" + getTimeStamp() + "\n【ME51主动】断开蓝牙连接_ _ "));
                    }

                    // APP主动模式下 延时13秒
                    if (mCycleTimes > 0 && appActiveMode) {
                        boolDisconnectDelay = false;
                        while (!boolDisconnectDelay) {
                            try {
                                Thread.sleep(1000);
                                Log.d(TAG, "--- waiting for [4] disconnect delay 13s over... ---");
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } else {
                    Log.e(TAG_TS, "Force Stop Thread!");
                    break;
                }
            }

            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n【测试结束】\n" +
                            "连接成功：" + totalCycleSuccess + "次\n" +
                            "连接失败：" + totalCycleFailure + "次\n" +
                            "通信成功：" + totalConnectSuccess + "次\n" +
                            "通信失败：" + totalConnectFailure + "次\n" +
                            "异常断开：" + totalUnexceptedDisconnect));
                }
            }, 800);
        }

        public void forceStopThread() {
            inRunning = false;
            boolContinueNextCycle = true;
            boolWaitingForME51Disconnect = true;
        }
    }

    /**
     * 主发送线程
     */
    private class SendDataThread extends Thread {

        private final String TAG_TS = "Send_T";
        private boolean inRunning;
        //        private int cycleTimes;     // 周期数
//        private int timesInCycle;   // 循环数/周期
        private boolean bDisconnectMode;

        public SendDataThread(boolean b) {
            inRunning = true;
            bDisconnectMode = b;
        }

        @Override
        public void run() {
            while (mTimersInCycle > 0) {     // 单个周期内
                if (Thread.currentThread().isInterrupted()) {
                    break;  // 强制退出
                }
                if (inRunning) {
                    Log.e(TAG, "##### [Cycle-" + mCycleTimes + "][Time-" + mTimersInCycle + "] #####");

                    EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n数据发送中...\n"));
                    if (mTimersInCycle == 1) {  // 最后一次
                        if (bDisconnectMode) {  // app active
                            if (mBluetoothLeService.sendData(getPackageViaCode(2))) {
                                // todo bus: 最后一次，发送失败-app
                                mHandler.sendEmptyMessage(0x01);
                                EventBus.getDefault().post(new EventReader("\n# [连接-" + mCycleTimes + "][最后一次通信-" + mTimersInCycle + "] --> 发送成功\n"));
                            } else {
                                EventBus.getDefault().post(new EventReader("\n# [连接-" + mCycleTimes + "][最后一次通信-" + mTimersInCycle + "] --> 发送失败\n"));
                                mHandler.sendEmptyMessage(0x03);
                            }
                        } else { // ME51 active
                            if (mBluetoothLeService.sendData(getPackageViaCode(3))) {
                                // todo bus: 最后一次，发送失败-me51
                                mHandler.sendEmptyMessage(0x01);
                                EventBus.getDefault().post(new EventReader("\n# [连接-" + mCycleTimes + "][最后一次通信-" + mTimersInCycle + "] --> 发送成功\n"));
                            } else {
                                EventBus.getDefault().post(new EventReader("\n# [连接-" + mCycleTimes + "][最后一次通信-" + mTimersInCycle + "] --> 发送失败\n"));
                                mHandler.sendEmptyMessage(0x03);
                            }
                        }
                    } else {  // 前N-1次
                        if (mBluetoothLeService.sendData(getPackageViaCode(1))) {
                            // todo bus: 前N-1次中
                            mHandler.sendEmptyMessage(0x01);
                            EventBus.getDefault().post(new EventReader("\n# [连接-" + mCycleTimes + "][通信-" + mTimersInCycle + "] --> 发送成功\n"));
                        } else {
                            EventBus.getDefault().post(new EventReader("\n# [连接-" + mCycleTimes + "][通信-" + mTimersInCycle + "] --> 发送失败\n"));
                            mHandler.sendEmptyMessage(0x03);
                        }
                    }

                    mTimersInCycle -= 1;

                    boolWaitingForOneCloseCycle = false;
                    while (!boolWaitingForOneCloseCycle) {
                        try {
                            Thread.sleep(1000);
                            Log.i(TAG, "--- waiting for [1]ME51 return all data ---");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    // todo Thread: 【一次发送结束，初始化接收缓冲区】
                    responseBuf.setLength(0);
                    receiveCount = 0;

                } else {
                    Log.e(TAG_TS, "Force Stop Thread!");

                    break;
                }
            }
            Log.e(TAG_TS, "one cycle over!!!!!!!!");
            boolContinueNextCycle = true;  // todo Thread: 【一个周期结束】
        }

        public void forceStopThread() {
            inRunning = false;
            boolContinueNextCycle = true;
            boolWaitingForME51Disconnect = true;
        }
    }


    // Handles various events fired by the Service.
    // ACTION_GATT_CONNECTED: connected to a GATT server.
    // ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
    // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
    // ACTION_DATA_AVAILABLE: received data from the device.  This can be a result of read or notification operations.
    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
//            final String extraData = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);
            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {  // todo jog: 连接成功
                Log.e(TAG, "#_# Connected");
                Date date = new Date(System.currentTimeMillis());
                Log.i("#GattReceiver", "连接成功:" + simpleDateFormat.format(date) + " | in millis:" + System.currentTimeMillis());

                try {
                    scanEndTime = simpleDateFormat.format(date);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                mProgressed = true;

                testScanning = false;
                btnScan.setText("开始扫描");
                llRootProgress.setVisibility(View.INVISIBLE);

                startActivity(new Intent(DemoActivity.this, ResultActivity.class));

                totalCycleSuccess += 1;

                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        if (mCycleTimes > 0) {
                            EventBus.getDefault().post(new EventReader("\n\n当前手机【Build.VERSION.SDK_INT ：" + Build.VERSION.SDK_INT + "】\n"));
                            EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n==================================\n已连接蓝牙：" + mBtName + "\n" +
                                    "连接序号：" + mCycleTimes + "    |    单次连接的通信次数：" + mTimersInCycle +
                                    (appActiveMode ? "\n断开模式: [APP主动]" : "\n断开模式: [ME51主动]") + "\n==================================\n"));

                            EventBus.getDefault().post(new EventReader("\n\n扫描开始时间 : " + scanStartTime + "\n扫描结束时间 : " + scanEndTime + "\n\n"));

                        } else {

                        }
                    }
                }, 200);

            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {  // todo jog: 主动断开
                Log.e(TAG, "#_# Disconnected");
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");// HH:mm:ss
                Date date = new Date(System.currentTimeMillis());
                Log.i("#GattReceiver", "断开连接:" + simpleDateFormat.format(date) + " | in millis:" + System.currentTimeMillis());
                dismissProgressDialog();
                if (isTimeOut) {
                    Toast.makeText(context, "TIME OUT!!\nConnection was terminated due to inactivity", Toast.LENGTH_SHORT).show();
                }
                isTimeOut = false;
                EventBus.getDefault().post(new EventReader("...成功\n"));

                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        boolDisconnectDelay = true;
                    }
                }, 13 * 1000);

                if (mCycleTimes > 0 && appActiveMode) {
                    EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n===== 延时13秒后开启下一轮扫描... =====\n"));
                }

            } else if (BluetoothLeService.ACTION_GATT_UNEXPECTED_DISCONNECT.equals(action)) { // todo jog: 异常断开device
                Log.e(TAG, "" + getTimeStamp() + "\n#_#  UNEXPECTED_DISCONNECT");

                totalUnexceptedDisconnect += 1;

                if (!boolWaitingForOneCloseCycle) {
//                    boolWaitingForOneCloseCycle = true;  // todo Exception: 数据接收 异常
                    EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n#_# 数据接收时 异常.\n"));
                }

                if (appActiveMode) {
                    // APP主动断开模式下，即为 真正的Exception
                    EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n#_# UNEXPECTED_DISCONNECT 2\n"));
                    if (!boolDisconnectDelay) {
//                    boolDisconnectDelay = true; // todo Exception: APP主动模式下 延时13秒 期间异常
                        EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n#_# 延时13秒期间 异常.\n"));
                    }
                } else {
                    // ME51断开模式下
                    if (mTimersInCycle < Integer.parseInt(etTimesInCycle.getText().toString().trim()) && mTimersInCycle > 0) {
                        // 一个周期内，通信未全部完成时
                        EventBus.getDefault().post(new EventReader("\n\n" + getTimeStamp() + "\n#_# UNEXPECTED_DISCONNECT 1\n"));
                    } else {
                        mHandler.sendEmptyMessage(0x22); // 停止等待ME51断开的超时定时器
//                        EventBus.getDefault().post(new EventReader("\n\n#_# 数据接收异常\n"));
//                        if (!boolContinueNextCycle) {
//                            boolContinueNextCycle = true;
//                        }
                        // CycleThread 线程内：一个周期内的最后一次，若为等待ME51断开中..
                        if (!boolWaitingForME51Disconnect) {
                            boolWaitingForME51Disconnect = true; // 则停止阻塞
                            EventBus.getDefault().post(new EventReader("# _ _断开成功！"));
                        }
                    }
                }
                dismissProgressDialog();
                currentProcess = MACHINE_IDLE;

                if (mTimer != null) mTimer.cancel();

                Toast.makeText(context, "Unexpected Disconnection\nDevice disconnected unintentionally.\nPlease try again.", Toast.LENGTH_SHORT).show();
//                CommonDialog.openSingleDialog(mContext, getString(R.string.err_unexpected_disconnect_title), getString(R.string.err_unexpected_disconnect_msg));

            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) { // todo jog: 发现蓝牙服务，可发数据
                Log.e(TAG, "#_# !! SERVICES_DISCOVERED !!");
                mBluetoothLeService.stopScan(mScanCallback, mLeScanCallback);

                // todo jog:
//                if (mBluetoothLeService.sendData(getPackageViaCode(2))) {
//                }
                mCommThread = new Thread(new SendDataThread(appActiveMode));
                mCommThread.start();

            } else if (BluetoothLeService.ACTION_GATT_SERVICES_ERROR.equals(action)) {
                Log.e(TAG, "#_# SERVICES_ERROR");
                CommonDialog.openSingleDialog(mContext, "UUID doesn't match", "Bluetooth Service UUID doesn't match\nUUID: " + Constants.SERVICE_UUID,
                        new DialogInterface.OnDismissListener() {
                            @Override
                            public void onDismiss(DialogInterface dialog) {
                                EventBus.getDefault().post(new EventReader("\n\nACTION_GATT_SERVICES_ERROR ----> disconnectBt()\n\n"));
                                disconnectBt();
                            }
                        });
            } else if (BluetoothLeService.ACTION_GATT_CHARACTERISTIC_ERROR.equals(action)) {
                Log.e(TAG, "#_# CHARACTERISTIC_ERROR");
                CommonDialog.openSingleDialog(mContext, "UUID doesn't match", "Bluetooth Characteristic UUID doesn't match\nUUID: " + Constants.CHARACTERISTIC_UUID,
                        new DialogInterface.OnDismissListener() {
                            @Override
                            public void onDismiss(DialogInterface dialog) {
                                EventBus.getDefault().post(new EventReader("\n\nACTION_GATT_CHARACTERISTIC_ERROR ----> disconnectBt()\n\n"));
                                disconnectBt();
                            }
                        });
            } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { // When data is available //接受到数据??
//                Log.e(TAG, "#_# DATA_AVAILABLE");
                isTimeOut = false;
            } else if (BluetoothLeService.ACTION_DATA_RETURNED.equals(action)) { // todo jog: On data returned 数据有返回
                Log.d(TAG, "#_# !!DATA_RETURNED !!");

                mHandler.sendEmptyMessage(0x11);

//                Log.i(TAG, "onReceive: responseBuf.toString()==" + responseBuf.toString());
                responseBuf.append(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));

                String tempS = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);
//                Log.i(TAG, "onReceive: tempS.toString()==" + tempS);
                Log.i(TAG, "onReceive: single package:length == " + tempS.length() + " | current total length == " + receiveCount);

                receiveCount += tempS.length();
                if (PACKAGE_ARRAY_SIZE == receiveCount / 3) {
                    if (validateData(currentSendDataType)) {
                        Log.e(TAG, "return ok");
                        EventBus.getDefault().post(new EventReader("...接收成功"));
                        totalConnectSuccess += 1;
                    } else {  // todo test else进不来了
                        Log.e(TAG, "return failure");
                        EventBus.getDefault().post(new EventReader("...接收失败, 实际接收：" + receiveCount / 3));
                        totalConnectFailure += 1;
                    }
                    boolWaitingForOneCloseCycle = true;  // todo Thread: 【一次数据收发 完成】

                } else if (PACKAGE_ARRAY_SIZE < receiveCount / 3) {
                    Log.e(TAG, "### ME51 return data overflow ###");
                    EventBus.getDefault().post(new EventReader("...接收失败, 实际接收：" + receiveCount / 3));
                }
//                byte[] tmpByte = Utils.hexStringToByteArray(responseBuf.toString().replace(" ", ""));
//                Log.i(TAG, "onReceive: tmpByte==" + Arrays.toString(tmpByte));
            }
        }
    };

    // 检验数据值
    private boolean validateData(int value) {
        String templateStr = "";
        switch (value) {
            case 1:
                templateStr = "11";
                break;
            case 2:
                templateStr = "22";
                break;
            case 3:
                templateStr = "33";
                break;
        }
//        int ee = countMatchTemplateStr(responseBuf.toString(), templateStr);
        checkCount = 0; // 恢复

        return true;  // todo test 去掉内容的检验
//        return PACKAGE_ARRAY_SIZE == ee;
    }

    private int countMatchTemplateStr(String str1, String str2) {
        if (!str1.contains(str2)) {
            return 0;
        } else if (str1.contains(str2)) {
            checkCount++;
            countMatchTemplateStr(str1.substring(str1.indexOf(str2) + str2.length()), str2);
            return checkCount;
        }
        return 0;
    }

    // 生成数据包
    private byte[] getPackageViaCode(int co) {
        currentSendDataType = co;
        byte[] tempArray = new byte[PACKAGE_ARRAY_SIZE];
        switch (co) {
            case 1:
                for (int i = 0; i < PACKAGE_ARRAY_SIZE; i++) {
                    tempArray[i] = 0x11;
                }
                break;
            case 2:
                for (int i = 0; i < PACKAGE_ARRAY_SIZE; i++) {
                    tempArray[i] = 0x22;
                }
                break;
            case 3:
                for (int i = 0; i < PACKAGE_ARRAY_SIZE; i++) {
                    tempArray[i] = 0x33;
                }
                break;
        }
        return tempArray;
    }

    /**
     * Bluetooth scan callback when sdk<=21
     */
    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {

                @Override
                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                    deviceFound = false;
                    Utils.printByteAsHex(scanRecord, "#scan record");

                    if (device != null && mBluetoothLeService != null) {
                        String sDeviceName = device.getName();
                        if (sDeviceName != null && sDeviceName.length() == 18) {
                            Log.i("#2_LeScanCallBack", "onLeScan: sDeviceName == " + sDeviceName);
                            if (sDeviceName.equals(mBtName)) {
                                mBluetoothLeService.stopScan(mScanCallback, mLeScanCallback);
                                deviceFound = true;
                            }
                        }
                        if (deviceFound) {
                            mDeviceName = sDeviceName;
                            deviceAddress = device.getAddress();
                            mBluetoothLeService.connect(deviceAddress);  // Core Connect
                            mBluetoothLeService.stopScan(mScanCallback, mLeScanCallback);
                        }
                    }
                }
            };

    private void dismissProgressDialog() {
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
        }
    }

    private void disconnectBt() {
        dismissProgressDialog();
        if (mBluetoothLeService != null) {
            mBluetoothLeService.disconnect();
        }
        currentProcess = MACHINE_IDLE;
        mProgressed = false;
        Log.e(TAG, "=== disconnectBt() ===");
    }

    private void requestLocationPermission() {
        // Here, thisActivity is the current activity
        if (!checkLocationPermission()) {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
        }
    }

    private boolean checkLocationPermission() {
        return !(ContextCompat.checkSelfPermission(this,
                android.Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(this,
                        android.Manifest.permission.ACCESS_FINE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(this,
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                        != PackageManager.PERMISSION_GRANTED
        );
    }

    /**
     * Bluetooth scan callback when sdk>21
     */
    protected void initScanCallback() {
        if (Build.VERSION.SDK_INT > 21) {
            mScanCallback = new ScanCallback() {//when connect BT then this callback will invoke
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    if (Build.VERSION.SDK_INT > 21) {
                        BluetoothDevice device = null;
                        if (result.getDevice() != null) {
                            device = result.getDevice();
                        }
                        if (device != null && mBluetoothLeService != null) {
                            String sDeviceName = device.getName();
                            if (sDeviceName != null && sDeviceName.length() == 18) {
                                Log.d("#1_ScanCallback", "onScanResult: sDeviceName == " + sDeviceName);

                                if (sDeviceName.equals(mBtName)) {
                                    mBluetoothLeService.stopScan(mScanCallback, mLeScanCallback);
                                    deviceAddress = device.getAddress();
                                    mBluetoothLeService.connect(deviceAddress);
                                    mBluetoothLeService.stopScan(mScanCallback, mLeScanCallback);
                                }
                            }
                        }
                    }
                }
            };
        }
    }

    /**
     * Scan bluetooth device
     *
     * @param enable
     * @param type   1 is from qr code
     *               2 is from input label ID
     */
    private void scanLeDevice(final boolean enable, final int type) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    if (mBluetoothLeService != null) {
                        mBluetoothLeService.stopScan(mScanCallback, mLeScanCallback);
                    }
                }
            }, SCAN_PERIOD);
            try {
                mTimer = new Timer();
                mTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        Handler h = new Handler(Looper.getMainLooper());
                        if (!mProgressed) {
                            h.post(new Runnable() {
                                public void run() {
                                    if (tryTimes != 5) {
                                        tryTimes++;
                                        scanLeDevice(true, type);
                                    } else {
                                        tryTimes = 1;
                                        dismissProgressDialog();
                                        if (type == 1) {
                                            Toast.makeText(mContext, "\"Machine not found\nPlease scan again", Toast.LENGTH_SHORT).show();
                                        } else {
                                            Toast.makeText(mContext, "\"Machine not found\nCheck the Machine Number and try again", Toast.LENGTH_SHORT).show();
                                        }

                                        totalCycleFailure += 1;
                                    }
                                }
                            });
                        }
                    }
                }, SCAN_PERIOD);
            } catch (Exception e) {
                e.printStackTrace();
                Log.w(TAG, "Timer was canceled");
            }
            mScanning = true;
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");// HH:mm:ss
            Date date = new Date(System.currentTimeMillis());
            if (mBluetoothLeService != null) {
                Log.i("#ScanLeDevice", "开始扫描:" + simpleDateFormat.format(date));
                Log.i("#ScanLeDevice", "开始扫描 in millis:" + System.currentTimeMillis());
                mBluetoothLeService.startScan(mScanCallback, mLeScanCallback);
            }
        } else {
            mScanning = false;
            if (mBluetoothLeService != null) {
                mBluetoothLeService.stopScan(mScanCallback, mLeScanCallback);
            }
        }
    }

    private void startME51DataTimerDown() {
        mME51DataResponseTimer = new CountDownTimer(30 * 1000, 1000) {
            @Override
            public void onTick(final long millisUntilFinished) {
            }

            @Override
            public void onFinish() {
                EventBus.getDefault().post(new EventReader("......接收超时！！\n" + getTimeStamp() + "\n"));
                boolWaitingForOneCloseCycle = true;
            }
        };
        mME51DataResponseTimer.start();
    }

    private void startME51ActiveDisconnectDown() {
        mME51DisconnectTimer = new CountDownTimer(30 * 1000, 1000) {
            @Override
            public void onTick(final long millisUntilFinished) {
            }

            @Override
            public void onFinish() {
                boolWaitingForME51Disconnect = true;
                EventBus.getDefault().post(new EventReader("\n" + getTimeStamp() + "\n......【ME51主动】断开超时了！！\n"));
            }
        };
        mME51DisconnectTimer.start();
    }

    private void handleSendDataFailure() {
        totalConnectFailure += 1;
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                boolWaitingForOneCloseCycle = true;
            }
        }, 600);
    }

    // 主线程
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(EventReader event) {
        switch (event.eventType) {
            case EVENT_TYPE_RESTORE_PAGE:

                break;
            case EVENT_TYPE_START_SCAN_ERROR:
                Toast.makeText(this, "startScan: 出错了", Toast.LENGTH_SHORT).show();
                break;
            case EVENT_TYPE_STOP_SCAN_ERROR:
                Toast.makeText(this, "stopScan: 出错了", Toast.LENGTH_SHORT).show();
                break;
        }
    }

    public String getVersionName(Context context) {
        try {
            PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return pInfo.versionName;
        } catch (Exception e) {
            e.printStackTrace();
            return "1.0";
        }
    }

    public int getVersionCode(Context context) {
        PackageInfo info = null;
        try {
            info = context.getPackageManager().getPackageInfo(
                    context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return 0;
        }
        return info.versionCode;
    }

    private String getTimeStamp() {
//        sdf.format(new Date())
        return System.currentTimeMillis() / 1000 + "";
    }
}
